#[macro_use] extern crate failure;
#[macro_use] extern crate log;

use std::os::raw::{c_char, c_int};
use std::str;

pub use ibm_mq_sys as mqi;

pub mod mqmessage;
pub mod mqueuemanager;
pub mod mqueue;

pub use mqmessage::MQMessage;
pub use mqueuemanager::{MQueueManager, MQOpenOpts};
pub use mqueue::{MQueue, MQGetMsgOpts, MQPutMsgOpts, MQTopic, MQSubDesc};

#[allow(dead_code)]
extern "C" {
    fn mqic_connect(qm: *const c_char,
                    channel: *const c_char,
                    host: *const c_char, user: *const c_char, password: *const c_char,
                    cc: *mut c_int, rc: *mut c_int) -> c_int;
    fn mqic_open(conn_handler: c_int, qm_name: *const c_char, obj_name: *const c_char,
                 cc: *mut c_int, rc: *mut c_int) -> c_int;
    fn mqic_disconnect(conn_handler: c_int, cc: *mut c_int, rc: *mut c_int);
    fn mqic_close(conn_handler: c_int, obj_handler: *const c_int, cc: *mut c_int, rc: *mut c_int);
    fn mqic_put(conn_handler: c_int, obj_handler: c_int,
                msg: *const c_char, msg_descriptor: mqi::MQMD,
                cc: *mut c_int, rc: *mut c_int);
    fn mqic_get(conn_handler: c_int, obj_handler: c_int,
                buff: *mut i8, bufflen: c_int,
                cc: *mut c_int, rc: *mut c_int) -> c_int;
    fn set_mqcd_default(mqcd: *mut mqi::MQCD);   
    fn set_mqcno_default(mqcno: *mut mqi::MQCNO);
    fn set_mqod_default(mqod: *mut mqi::MQOD);
    fn set_mqgmo_default(mqgmo: *mut mqi::MQGMO);
    fn set_mqpmo_default(mqpmo: *mut mqi::MQPMO);
    fn set_mqmd_default(mqmd: *mut mqi::MQMD);
    fn set_mqsd_default(mqmd: *mut mqi::MQSD);
}

#[derive(Debug, Fail)]
pub enum MqError{
    #[fail(display = "Failed to connect, CC: {}, RC: {}", cc, rc)]
    ConnectFailed { cc: ComplCode, rc: ReasonCode },
    #[fail(display = "Failed to open {}, CC: {}, RC: {}", obj, cc, rc)]
    OpenFailed { obj: String, cc: ComplCode, rc: ReasonCode },
    #[fail(display = "Failed to PUT msg to {}, CC: {}, RC: {}\n{:?}", obj, cc, rc, msg)]
    PutFailed{ obj: String, msg: String, cc: ComplCode, rc: ReasonCode },
    #[fail(display = "Failed to GET msg from {}, CC: {}, RC: {}", obj, cc, rc)]
    GetFailed{ obj: String, cc: ComplCode, rc: ReasonCode },
    #[fail(display = "Failed to subscribe to {}, CC: {}, RC: {}", obj, cc, rc)]
    SubscribeFailed{ obj: String, cc: ComplCode, rc: ReasonCode }
}

fn strcpy(inp: &[u8], out: &mut [i8], len: usize){
    if len > 0 {
        for i in 0..len {
            out[i] = inp[i] as i8
        }
    }
}

#[derive(Debug,PartialEq)]
pub struct ComplCode(i32);
impl ComplCode {
    pub fn is_ok(&self) -> bool {
        self.0 == mqi::MQCC_OK
    }
}
impl std::fmt::Display for ComplCode {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let code = mqi::cc_to_desc_string(self.0);
        write!(f, "{} - {}", self.0 as i32, code)
    }
}


#[derive(Debug,PartialEq)]
pub struct ReasonCode(i32);
impl ReasonCode {
    pub fn is_ok(&self) -> bool {
        self.0 == mqi::MQRC_NONE
    }
}
impl std::fmt::Display for ReasonCode {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let code = mqi::rc_to_desc_string(self.0);
        write!(f, "{} - {}", self.0 as i32, code)
    }
}
